// Object.prototype.toString.call('').slice(8, -1) 可以用来判断类型

function deepClone(origin, target) {
	let tar = target || {}
	let toStr = Object.prototype.toString
	let arrType = '[object Array]'
	for (let k in origin) {
		if (origin.hasOwnProperty(k)) {
			if (typeof origin[k] === 'object' && origin[k] !== null) {
				tar[k] = toStr.call(origin[k]) === arrType ? [] : {}
				deepClone(origin[k], tar[k])
			} else {
				tar[k] = origin[k]
			}
		}
	}
	return tar
}

function deepClone(origin) {
	// null == undefined true
	if (origin == undefined || typeof origin !== 'object') {
		return origin
	}

	if (origin instanceof Date) {
		return new Date(origin)
	}

	if (origin instanceof RegExp) {
		return new RegExp(origin)
	}

	const target = new origin.constructor()
	for (let k in origin) {
		if (origin.hasOwnProperty(k)) {
			target[k] = deepClone(origin[k])
		}
	}
	return target
}

// 深拷贝：对 对象内部进行深拷贝，支持 Array、Date、RegExp、DOM
const deepCopy = (sourceObj) => {
  // 如果不是对象则退出（可停止递归）
  if(typeof sourceObj !== 'object') return;
  // 深拷贝初始值：对象/数组
  let newObj = (sourceObj instanceof Array) ? [] : {};
  // 使用 for-in 循环对象属性（包括原型链上的属性）
  for (let key in sourceObj) {
	// 只访问对象自身属性
	if (sourceObj.hasOwnProperty(key)) {
	  // 当前属性还未存在于新对象中时
	  if(!(key in newObj)) {
		if (sourceObj[key] instanceof Date) {
		  // 判断日期类型
		  newObj[key] = new Date(sourceObj[key].getTime());
		} else if (sourceObj[key] instanceof RegExp) {
		  // 判断正则类型
		  newObj[key] = new RegExp(sourceObj[key]);
		} else if ((typeof sourceObj[key] === 'object') && sourceObj[key].nodeType === 1 ) {
		  // 判断 DOM 元素节点
		  let domEle = document.getElementsByTagName(sourceObj[key].nodeName)[0];
		  newObj[key] = domEle.cloneNode(true);
		} else {
		  // 当元素属于对象（排除 Date、RegExp、DOM）类型时递归拷贝
		  newObj[key] = (typeof sourceObj[key] === 'object') ? deepCopy(sourceObj[key]) : sourceObj[key];
		}
	  }
	}
  }
  return newObj;
}

function deepClone(obj) {
	let objClone
	if (obj && typeof obj === 'object') {
		objClone =  Array.isArray(obj) ? [] : {};
		// let objClone = obj instanceof Array ? [] : {};
		// let objClone = objClone.constructor === Array ? [] : {};
		for(let key in obj) {
			if (obj[key] && typeof obj[key] === 'object') {
				objClone[key] = deepClone(obj[key]);
			} else {
				objClone[key] = obj[key]
			}
		}
	} else {
		objClone = obj
	}
	return objClone;
}

// deepCopy 函数测试效果
const objA = {
  name: 'jack',
  birthday: new Date(),
  pattern: /jack/g,
  body: document.body,
  others: [123, 'coding', new Date(), /abc/gim]
};

const objB = deepCopy(objA);
console.log(objA === objB); // false
console.log(objA.others === objB.others); // false
console.log(objA, objB); // 对象内容一样
    
// WeakMap 相对于普通的 Map，也是键值对集合，只不过 WeakMap 的 key 只能是非空对象（non-null object）。
// WeakMap 对它的 key 仅保持弱引用，也就是说它不阻止垃圾回收器回收它所引用的 key。WeakMap 最大的好处是可以避免内存泄漏。
// 一个仅被WeakMap 作为 key 而引用的对象，会被垃圾回收器回收掉。

    